
#include "area.h"
#include "avatar.h"
#include "commandTable.h"
#include "commandTable-default.h"
#include "commands-redit.h"
#include "display.h"
#include "handler.h"
#include "room.h"
#include "symphony.h"
#include "world.h"

/*
Cmd::Cmd( void ) {
  name( "" );
  return;
}

bool Cmd::execute( Creature* creature, const std::string& args ) {

  return true;
}
*/

CmdQuit::CmdQuit( void ) {
  name( "quit" );
  return;
}

bool CmdQuit::execute( Creature* creature, const std::string& args ) {
  if ( creature->save() ) {
    creature->disconnected( true );
    World::Instance().bigBrother( creature, ADMIN_BIGBRO_LOGINS, "%s has logged out.", creature->name().c_str() );
    World::Instance().playerLog( NOTICE, LOG_PLAYER, "%s (%lu) logged out", creature->name().c_str(), creature->ID(), ((Avatar*)creature)->socket()->getIP().c_str() );
  } else {
    creature->send( "There was a problem saving your profile data.  Try again in a minute." );
    return false;
  }
  return true;
}

CmdReboot::CmdReboot( void ) {
  name( "reboot" );
  level( CREATOR );
  syntax( "syntax: reboot reboot" );
}

bool CmdReboot::execute( Creature* creature, const std::string& args ) {
  if ( args == "reboot" ) {
    return World::Instance().reboot( creature );
  } else {
    creature->send( syntax() );
    return false;
  }
}

CmdRedit::CmdRedit( void ) {
  name( "redit" );
  level( BUILDER );
  syntax( "syntax: redit create <vnum>\n        redit" );
  return;
}

bool CmdRedit::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 3 );
  RCmdCreate create;
  CmdGoto go;

  if ( pieces.size() == 2 ) {
    if ( pieces[0] == "create" ) {
      // Everything looks clear; create the room...
      if ( create.execute( creature, pieces[1] ) ) {
        go.execute( creature, pieces[1] );
        creature->mode( MODE_REDIT );
        ((Avatar*)creature)->pushHandler( new ReditHandler( (Avatar*)creature ) );
      }
    } else {
      creature->send( syntax() );
      return false;
    }
  } else if ( pieces.empty() ) {
    // Check permissions...
    if ( !World::Instance().hasPermission( creature->room()->area(), (Avatar*)creature ) ) {
      creature->send( "You don't have permissions to this room." );
      return false;
    }
    // Make sure no one else is editing the room...
    for ( std::map<std::string,Avatar*>::iterator it = World::Instance().getAvatars().begin(); it != World::Instance().getAvatars().end(); ++it ) {
      if ( it->second->mode() == MODE_REDIT && it->second->room() == creature->room() ) {
        creature->send( "Sorry, %s is currently editing room %lu.", creature->seeName( ((Creature*)it->second) ).c_str(), creature->room()->vnum() );
        return false;
      }
    }
    // Looks good; send them to redit...
    creature->send( "You're editing Room %lu.", creature->room()->vnum() );
    creature->mode( MODE_REDIT );
    ((Avatar*)creature)->pushHandler( new ReditHandler( (Avatar*)creature ) );
  } else {
    creature->send( syntax() );
    return false;
  }

  return true;
}

CmdReply::CmdReply( void ) {
  name( "reply" );
  return;
}

bool CmdReply::execute( Creature* creature, const std::string& args ) {
  std::string text = Regex::trim( args );
  Creature* target = NULL;

  if ( creature->replyTo().empty() || ( target = World::Instance().findAvatar( creature->replyTo() ) ) == NULL ) {
    creature->send( "They aren't here." );
    return false;
  }

  if ( !target->channel( CHAN_TELL ) ) {
    creature->send( "They're not receiving tells right now." );
    return false;
  }

  target->send( "%s replies to you, \"{Y%s{x\"", target->seeName( creature ).c_str(), text.c_str() );
  creature->send( "You reply to %s, \"{Y%s{x\"", creature->seeName( target ).c_str(), text.c_str() );

  return true;
}

CmdRlist::CmdRlist( void ) {
  name( "rlist" );
  level( BUILDER );
  syntax( "syntax: rlist <areaID>\n        rlist <first vnum> <last vnum>\n        rlist <string>\n        rlist /<regex>\n  [Enclose 'search string' or '/regular expression' in quotes if it contains any spaces]" );
  return;
}

bool CmdRlist::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  std::vector<Room*> rooms;
  Area* area = NULL;
  unsigned long low = 0;
  unsigned long high = 0;
  std::string search;
  std::string output;
  char buffer[MAX_BUFFER];

  if ( pieces.size() == 1 ) {
    if ( Regex::match( "^[0-9]+$", pieces[0] ) ) {
      // We got an areaID...
      if ( ( area = World::Instance().findArea( estring(pieces[0]) ) ) == NULL ) {
        creature->send( "That area couldn't be found." );
        return false;
      }
      for ( std::map<unsigned long,Room*>::iterator r_it = area->rooms().begin(); r_it != area->rooms().end(); ++r_it ) {
        rooms.push_back( r_it->second );
      }
    } else {
      if ( pieces[0][0] == '/' ) {
        pieces[0].erase( 0, 1 );
        // This search is a regex...
        for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
          for ( std::map<unsigned long,Room*>::iterator r_it = (*a_it)->rooms().begin(); r_it != (*a_it)->rooms().end(); ++r_it ) {
            if ( Regex::match( pieces[0], r_it->second->name() ) ) {
              rooms.push_back( r_it->second );
            }
          }
        }
      } else {
        search = Regex::lower(pieces[0]);
        // We got a search string...
        for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
          for ( std::map<unsigned long,Room*>::iterator r_it = (*a_it)->rooms().begin(); r_it != (*a_it)->rooms().end(); ++r_it ) {
            if ( Regex::lower(r_it->second->name()).find( search ) != std::string::npos ) {
              rooms.push_back( r_it->second );
            }
          }
        }
      }
    }
  } else if ( pieces.size() == 2 ) {
    /* We're looking for a vnum range here */
    // Grab our range values...
    low = estring(pieces[0]);
    high = estring(pieces[1]);
    // Check our range...
    if ( !high || low >= high ) {
      creature->send( "Invalid vnum range." );
      return false;
    }
    if ( low+400 < high ) {
      creature->send( "The maximum vnum range is 400." );
      return false;
    }
    // Grab the rooms...
    for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
      for ( std::map<unsigned long,Room*>::iterator r_it = (*a_it)->rooms().begin(); r_it != (*a_it)->rooms().end(); ++r_it ) {
        if ( r_it->second->vnum() >= low && r_it->second->vnum() <= high ) {
          rooms.push_back( r_it->second );
        }
      }
    }
  } else {
    creature->send( syntax() );
    return false;
  }

  if ( rooms.empty() ) {
    creature->send( "No matches for \"%s\"", pieces[0].c_str() );
    return false;
  }

  output.append( " ({carea{x) [{y room{x] {gname{x\n -------------------\n" );
  for ( std::vector<Room*>::iterator it = rooms.begin(); it != rooms.end(); ++it ) {
    sprintf( buffer, " ({c%4lu{x) [{y%5lu{x] {g%s{x\n", (*it)->area()->ID(), (*it)->vnum(), (*it)->name().c_str() );
    output.append( buffer );
  }

  creature->send( output );
  return true;
}

CmdSave::CmdSave( void ) {
  name( "save" );
  return;
}

bool CmdSave::execute( Creature* creature, const std::string& args ) {
  if ( creature->save() ) {
    creature->send( "Information saved." );
    return true;
  } else {
    creature->send( "There was a problem saving your information." );
    return false;
  }
}

CmdSay::CmdSay( void ) {
  name( "say" );
  return;
}

bool CmdSay::execute( Creature* creature, const std::string& args ) {
  std::string text = Regex::trim(args);

  if ( text.empty() ) {
    creature->send( "Say what?" );
    return false;
  }

  creature->room()->send( "$p says '{G$s{x'", creature, (void*)text.c_str() );
  creature->send( "You say '{G%s{x'", text.c_str() );

  return true;
}

CmdSockets::CmdSockets( void ) {
  name( "sockets" );
  level( BUILDER );
  return;
}

bool CmdSockets::execute( Creature* creature, const std::string& args ) {
  estring output;
  char buffer[MAX_BUFFER];

  sprintf( buffer, "  {x%-15s{C%-10s{W%-20s\n", "Name", "Socket", "IP Address" );
  output.append( buffer );
  output.append( "  ---------------------------------------------\n" );

  for ( std::map<std::string,Avatar*>::const_iterator it = World::Instance().getAvatars().begin(); it != World::Instance().getAvatars().end(); ++it ) {
    if ( creature->canSee( it->second ) == SEE_NAME ) {
      sprintf( buffer, "  {x%-15s{C%-10d{W%-20s\n", it->second->name().c_str(), it->second->socket()->getFd(), it->second->socket()->getIP().c_str() );
      output.append( buffer );
    }
  }

  creature->send( output );

  return true;
}

CmdShutdown::CmdShutdown( void ) {
  name( "shutdown" );
  level( CREATOR );
  return;
}

bool CmdShutdown::execute( Creature* creature, const std::string& args ) {
  World::Instance().exists( false );
  return true;
}

CmdSummon::CmdSummon( void ) {
  name( "summon" );
  level( BUILDER );
  syntax( "syntax: summon <player>\n        summon <mob>" );
  return;
}

bool CmdSummon::execute( Creature* creature, const std::string& args ) {
  Creature* target = NULL;
  Room* from = NULL;
  Room* to = creature->room();
  CmdLook look;

  if ( args.empty() ) {
    creature->send( syntax() );
    return false;
  }

  // Aquire target...
  if ( ( target = World::Instance().findCreature( args ) ) == NULL ) {
    creature->send( "They're not around at the moment." );
    return false;
  }

  // Check permissions...
  if ( !creature->canAlter( target ) ) {
    creature->send( "You can't summon %s.", target->name().c_str() );
    target->send( "%s has attempted to summon you.", creature->name().c_str() );
    return false;
  }

  // Summon...
  from = target->room();
  target->send( "You've been summoned by %s.\n", target->seeName( creature ).c_str() );
  from->send_cond( "$p disappears.", target );
  from->remove( target );
  to->add( target );
  target->room( to );
  to->send_cond( "$p appears.", target );
  look.execute( target, "" );

  return true;
}

